#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <time.h>
#include <signal.h>


/* some magic numbers */
#define LISTENPORT 50080   /* the port to listen on for commands */
#define MAXPENDING 5      /* Max connection requests */
#define BUFFSIZE 10000    /* The largest message that can be sent to this server */
#define MAXCHECKARGS 3    /* the maximum number of arguments that can be sent from command_handler 
			     to check_control */
#define MAXCHECKALLOW 5   /* the number of arguments command_handler recognises for check-* */

/* error code definitions */
#define NO_ERROR           0 /* everything worked */

#define SHORT_MESG         1 /* the message sent to the server is too short */
#define SHORT_MESG_ERR "message too short"

#define MALFORMED_DATA     2 /* the data request does not follow variable=data*/
#define MALFORMED_DATA_ERR "malformed data request"

#define MALFORMED_DATE     3 /* the start date does not follow either yyyy-mm-dd or yyyymmdd */
#define MALFORMED_DATE_ERR "malformed starting date"

#define MONTH_RANGE        4 /* the start month is not valid */
#define MONTH_RANGE_ERR "the month must be a number between 1 and 12"

#define DATE_RANGE         5 /* the start day-of-month is not valid */
#define DATE_RANGE_ERR  "the day-of-month must be a number between 1 and 31, and be valid for the supplied month"

#define IN_THE_PAST        6 /* the starting date is in the past */
#define IN_THE_PAST_ERR "the starting date/time is in the past"

#define MALFORMED_TIME     7 /* the start time does not follow either hh:mm:ss.s or hh:mm:ss or hhmmss.s or hhmmss */
#define MALFORMED_TIME_ERR "malformed starting time"

#define DATE_NOT_SET       8 /* the starting date must be set before the starting time */
#define DATE_NOT_SET_ERR "the starting date must be set before setting the starting time"

#define HOUR_RANGE         9 /* the start hour is not valid */
#define HOUR_RANGE_ERR "the hour must be a number between 0 and 23"

#define MINUTE_RANGE      10 /* the start minute is not valid */
#define MINUTE_RANGE_ERR "the minute must be a number between 0 and 59"

#define SECOND_RANGE      11 /* the start second is not valid */
#define SECOND_RANGE_ERR "the second must be a number between 0.0 and 59.9"

#define BAD_COMPRESSION   12 /* the compression string is not valid */
#define BAD_COMPRESSION_ERR "the compression settings are not valid"

#define BAD_VSIB_MODE     13 /* the vsib mode is not valid */
#define BAD_VSIB_MODE_ERR "the specified vsib mode is not valid"

#define BAD_BANDWIDTH     14 /* the bandwidth is not valid */
#define BAD_BANDWIDTH_ERR "the specified bandwidth is not valid"

#define BAD_DATA          15 /* the data variable is not valid */
#define BAD_DATA_ERR "the specified data variable is not valid"

#define INVALID_S2_MODE   16 /* the specified S2 mode is invalid */
#define INVALID_S2_MODE_ERR "the specified mode of the S2 recorder is not valid"

#define UNKNOWN_COMMAND   17 /* the command is not valid */
#define UNKNOWN_COMMAND_ERR "the command issued is not valid"

#define FILE_UNREADABLE   18 /* the requested file was not able to be read */
#define FILE_UNREADABLE_ERR "unable to open the recorder settings file for reading"

#define FILE_UNWRITABLE   19 /* the requested file was not able to be written */
#define FILE_UNWRITABLE_ERR "unable to open the recorder settings file for writing"

#define ALREADY_RECORDING 20 /* a request to start recording was made while the recorder was running */
#define ALREADY_RECORDING_ERR "request to start recording denied: recorder is already running"

#define RECORDING_TIME    21 /* the requested recording time is too low */
#define RECORDING_TIME_ERR "the requested recording time is less than 1 hour"

#define DIRECTORY_NOT_SET 22 /* the directory name has not been set */
#define DIRECTORY_NOT_SET_ERR "the output directory has not been specified"

#define FILENAME_NOT_SET  23 /* the filename prefix has not been set */
#define FILENAME_NOT_SET_ERR "the output filename prefix has not been specified"

#define DIRECTORY_INVALID 24 /* the name of the directory cannot be used */
#define DIRECTORY_INVALID_ERR "the name specified for the output directory is being used by a non-directory"

#define MKDIR_FAILED      25 /* the output directory was unable to be created */
#define MKDIR_FAILED_ERR "the output directory was unable to be created"

#define CHDIR_FAILED      26 /* could not chdir into the output directory */
#define CHDIR_FAILED_ERR "could not chdir into the output directory"

#define SETTINGS_GONE     27 /* the recorder settings file was not written, or was deleted */
#define SETTINGS_GONE_ERR "the recorder settings file was not written as expected, or has been deleted"

#define UNEXPECTED_EOF    28 /* there was not enough information in the recorder settings file */
#define UNEXPECTED_EOF_ERR "the recorder settings file is corrupt"

#define CORRUPT_SETTINGS  29 /* the recorder settings file was not accepted by the data handler */
#define CORRUPT_SETTINGS_ERR "the recorder settings file has been corrupted"

#define NOT_RECORDING     30 /* a request was made to stop the recorder, but recording has not started */
#define NOT_RECORDING_ERR "request to stop recording denied: recorder not currently running"

#define STOP_FAILED       31 /* the stop recorder request failed */
#define STOP_FAILED_ERR "unable to stop recorder process"

#define MALFORMED_REQUEST 32 /* the request to the server was not specified correctly */
#define MALFORMED_REQUEST_ERR "malformed request"

#define RESET_FAILED      33 /* the requested data could not be reset to defaults */
#define RESET_FAILED_ERR "the requested data could not be reset to its default value"

#define INVALID_RESET     34 /* cannot reset data variable because it doesn't exist */
#define INVALID_RESET_ERR "cannot reset data variable because it doesn't exist"

#define TOO_MANY_ARGS     35 /* too many arguments were specified for the data checking */
#define TOO_MANY_ARGS_ERR "more than 2 arguments were given for the data checking command"

#define BAD_CHECK_ARGS    36 /* two of the exclusive check arguments were specified at the same time */
#define BAD_CHECK_ARGS_ERR "two or more of the exclusive check arguments were specified at the same time"

#define MALFORMED_RECTIME 37 /* the recording time doesn't look like it should */
#define MALFORMED_RECTIME_ERR "the specified recording time is invalid"

#define FREESPACE         38 /* the free space on the disk cannot be determined */
#define FREESPACE_ERR "the amount of free space on the disk cannot be determined"

#define STATUS_INVALID    39 /* requested an unrecognised status mode */
#define STATUS_INVALID_ERR "the requested status mode is invalid"

#define STATUS_COMPLETE   40 /* the status request was completed successfully - a dummy error code */

#define LATEST_FAIL       41 /* can't determine the latest files */
#define LATEST_FAIL_ERR "unable to determine the latest recorded files"

#define CHECK_FORK_FAIL   42 /* can't fork the checker process */
#define CHECK_FORK_FAIL_ERR "unable to begin a forked process to run checker"

/* recorder control flags */
#define RECSTART  -10 /* starts the recorder */
#define RECSTOP   -20 /* stops the recorder */

/* data verification flags */
#define CHECKALL     -30 /* checks all files in the directory */
#define CHECKLATEST  -40 /* checks only the last file to be written */

/* status checking flags */
#define STATUS_RECORD -50 /* check the status of the recorder */
#define STATUS_CHECK  -60 /* check the status of the checker */

/* data reset flags */
#define RESET_RECORD_TIME         1
#define RESET_RECORD_START_DATE   2
#define RESET_RECORD_START_TIME   4
#define RESET_DIRECTORY_NAME      8
#define RESET_FILENAME_PREFIX    16
#define RESET_COMPRESSION        32
#define RESET_VSIB_MODE          64
#define RESET_BANDWIDTH         128
#define RESET_ALL               255
#define RESET_INITIAL           511

/* structure to hold the required data variables */
typedef struct _recorder {
  char  record_time[BUFFSIZE];       /* the time to record data for */
  char  record_start_date[BUFFSIZE]; /* the date to start the recording */
  char  record_start_time[BUFFSIZE]; /* the time to start the recording */
  char  directory_name[BUFFSIZE];    /* the directory to put the files in */
  char  filename_prefix[BUFFSIZE];   /* the prefix for the output filenames */
  char  compression[5];              /* the channels to record the data for */
  int   vsib_mode;                   /* the vsib mode for bit length */
  int   bandwidth;                   /* the recording bandwidth */
  int   process_id;                  /* the PID of the recorder process */
  char  status_recorder[BUFFSIZE];   /* the status of the recorder */
  char  status_checker[BUFFSIZE];    /* the status of the checker */
  int   in_dir;                      /* have we already changed into the output directory (1=yes,0=no) */
} recorder;

/* function definitions */
void Die(char *mess, int sock);
void PrintStatus(char *mess);
void HandleClient(int sock,recorder *settings);
void send_confirmation(int errorcode,char *errormessage,int sock);
int message_handler(char *message,char *failure);
int data_handler(char *data,char *failure,recorder *settings);
int command_handler(char *data,char *failure,recorder *settings);
int status_control(int mode,recorder *settings,char *failure);
int check_control(int mode,recorder *settings,char *failure,char check_args[2][BUFFSIZE]);
int recorder_control(int command,recorder *settings,char *failure);
int check_date(int year,int month,int date);
int check_time(int year,int month,int date,int hour,int minute,float second);
int xmody(int x,int y);
int LoadSettings(recorder *settings,int RESET,char *failmsg);
int LoadRecorderSettings(recorder *settings,char *failmsg);
int WriteRecorderSettings(recorder *settings,char *failure);
int WriteRecorderPID(recorder *settings,char *failure);
int UpdateRecorderStatus(recorder *settings,char *failure);
void child_handler(int sig);
int checkrunning(int pid);
